﻿using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Linq;

public static class PSDUIImporter
{

    static string rootPath;
    static Sprite[] images;
    static bool[] IsHorizontal = new bool[] { true, true, false, false };

    [MenuItem("NGUI/Set Selected Anchor to Current")]
    static void SetAllAnchorToCurrent()
    {
        SetAnchorToCurrent(4);
    }

    [MenuItem("Window/Refresh Assets")]
    static void RefreshAssets()
    {
        AssetDatabase.Refresh();
    }

    [MenuItem("NGUI/Set Left-Right Anchor to Current")]
    static void SetLeftRightAnchorToCurrent()
    {
        SetAnchorToCurrent(2);
    }

    static void SetAnchorToCurrent(int count)
    {
        Object[] selected = Selection.GetFiltered((typeof(GameObject)), SelectionMode.ExcludePrefab).Where(go => ((GameObject)go).GetComponent<UIRect>() != null).ToArray();
        if (selected.Length == 0)
        {
            Debug.Log("Nothing selected.");
        }
        else
        {
            foreach (var o in selected)
            {
                GameObject go = (GameObject)o;
                GameObject parent = go.transform.parent.gameObject;
                Transform parentTrans = parent.transform;
                UIRect myRect = go.GetComponent<UIRect>();


                UIRect targetRect = parent.GetComponent<UIRect>();

                if (targetRect == null)
                {
                    targetRect = parent.transform.parent.GetComponent<UIRect>();
                    parentTrans = parent.transform.parent;
                }

                Vector3[] sides = targetRect.GetSides(myRect.cachedTransform);
                float width = sides[2].x - sides[0].x;
                float height = sides[1].y - sides[3].y;
                UIRect.AnchorPoint[] anchors = new UIRect.AnchorPoint[] {
					myRect.leftAnchor,
					myRect.rightAnchor,
					myRect.bottomAnchor,
					myRect.topAnchor
				};

                for (int index = 0; index < count; index++)
                {
                    float total;
                    anchors[index].target = parentTrans;
                    if (IsHorizontal[index])
                    {
                        total = width;
                        UIRectEditor.UpdateHorizontalAnchor(myRect, anchors[index], true);
                    }
                    else
                    {
                        total = height;
                        UIRectEditor.UpdateVerticalAnchor(myRect, anchors[index], true);
                    }

                    // Final position after both relative and absolute values are taken into consideration
                    float final = Mathf.Floor(0.5f + Mathf.Lerp(0f, total, anchors[index].relative) + anchors[index].absolute);

                    final = final / (total);

                    anchors[index].Set(final, 0f);
                }
                NGUITools.SetDirty(myRect);
            }
        }
    }

    /*[MenuItem("Assets/PSD TO NGUI/show info")]
    static void showInfo ()
    {
        Object o = Selection.activeObject;
        rootPath = AssetDatabase.GetAssetPath (o);
        Debug.Log (rootPath);
        Debug.Log (o.GetType ());
        Sprite[] images = AssetDatabase.LoadAllAssetsAtPath (rootPath).OfType<Sprite> ().ToArray ();
        Debug.Log (images.Length);
    }*/

    [MenuItem("Assets/PSD TO NGUI/Import PSD Data")]
    static void ImportPSDData()
    {
        Object o = Selection.activeObject;
        rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(o));

        Hashtable ht = ((TextAsset)o).text.hashtableFromJson();
        string src = ht["src"] as string;
        if (src == null)
        {
            src = ht["name"] as string;
        }

        images = getSingleImages(rootPath, src);
        if (images == null)
            return;

        UIPanel panel = GetOrCreatePanel((string)ht["name"]);
        ArrayList children = ht["children"] as ArrayList;
        depth = 1;
        foreach (Hashtable child in children)
        {
            ApplyWidget(panel.gameObject, ht, child);
        }
    }

    /// <summary>
    /// 使用TexturePacker图集
    /// </summary>
    /// <param name="rootPath"></param>
    /// <param name="src"></param>
    /// <returns></returns>
    private static Sprite[] getTPImages(string rootPath, string src)
    {
        Object[] allAssets = AssetDatabase.LoadAllAssetsAtPath(rootPath + "/" + src + ".png");
        if (allAssets.Length == 0)
        {
            Debug.LogError("图集文件 " + src + " 未找到");
            return null;
        }
        return allAssets.OfType<Sprite>().ToArray();
    }

    /// <summary>
    /// 使用Unity自带图片打包
    /// </summary>
    /// <param name="rootPath"></param>
    /// <param name="src"></param>
    /// <returns></returns>
    private static Sprite[] getSingleImages(string rootPath, string src)
    {
        string[] imgPathes = Directory.GetFiles(Application.dataPath + rootPath.Substring(6) + "/"+src, "*.png", SearchOption.AllDirectories).Select(s => "Assets" + s.Replace(Application.dataPath, "").Replace("\\", "/")).ToArray();
        string packingTag = "UI_" + src;
        foreach (var path in imgPathes)
        {
            TextureImporter texImp = AssetImporter.GetAtPath(path) as TextureImporter;
            if (texImp.spritePackingTag == packingTag)
            {
                continue;
            }
            texImp.spritePackingTag = packingTag;
            texImp.textureType = TextureImporterType.Sprite;
            AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
        }

        return imgPathes.Select(s => AssetDatabase.LoadAssetAtPath(s, typeof(Sprite))).OfType<Sprite>().ToArray();
    }

    static float ToFloat(System.Object obj)
    {
        return float.Parse(obj.ToString());
    }

    static int depth;
    static void ApplyWidget(GameObject parent, Hashtable parentCfg, Hashtable widgetCfg)
    {
        depth++;
        string name = (string)widgetCfg["name"];
        string type = (string)widgetCfg["UIType"];
        string imageName;
        GameObject go = null;
        Vector3 widgetPos = new Vector3(ToFloat(widgetCfg["x"]) - ToFloat(parentCfg["x"]), ToFloat(widgetCfg["y"]) - ToFloat(parentCfg["y"]));
        switch (type)
        {
            case "Sprite":
            case "Button":
                UI2DSprite sprite = GetOrCreate2DSprite(parent, name, type == "Button");
                go = sprite.gameObject;
                imageName = (string)widgetCfg["img"];
                UIBasicSprite.Type spriteType = UIBasicSprite.Type.Simple;
                if ((string)widgetCfg["type"] == "sliced")
                {
                    spriteType = UIBasicSprite.Type.Sliced;
                }
                Sprite targetSprite = images.FirstOrDefault((img => img.name == imageName));
                if (targetSprite == null && imageName!=null)
                {
                    Debug.LogError("The sprite \"" + imageName + "\" specified by " + name + " is not found.");
                }
                else
                {
                    sprite.sprite2D = targetSprite;
                }
                if (sprite.type != spriteType && spriteType == UIBasicSprite.Type.Simple)
                    sprite.type = spriteType;
                sprite.transform.localPosition = widgetPos;
                sprite.width = (int)float.Parse(widgetCfg["width"].ToString());
                sprite.height = (int)float.Parse(widgetCfg["height"].ToString());
                sprite.depth = depth;
                if (type == "Button")
                {
                    NGUITools.AddWidgetCollider(sprite.gameObject);
                    sprite.gameObject.AddMissingComponent<UIButton>();
                }
                break;
            case "Label":
                UILabel label = GetOrCreateLabel(parent, name);
                go = label.gameObject;
                label.transform.localPosition = widgetPos;
                label.width = (int)float.Parse(widgetCfg["width"].ToString());
                label.height = (int)float.Parse(widgetCfg["height"].ToString());
                label.depth = depth + 1000;
                string text = (string)widgetCfg["text"];
                if (text != null)
                {
                    label.text = text;
                }
                break;
            case "Empty":
            case "Slider":
            case "Progress":
                UIWidget empty = GetOrCreateEmpty(parent, name);
                go = empty.gameObject;
                empty.transform.localPosition = widgetPos;
                empty.width = (int)float.Parse(widgetCfg["width"].ToString());
                empty.height = (int)float.Parse(widgetCfg["height"].ToString());
                empty.depth = depth;
                if (type == "Slider")
                {
                    go.AddMissingComponent<UISlider>();
                }
                else if (type == "Progress")
                {
                    go.AddMissingComponent<UIProgressBar>();
                }
                break;
            case "ScrollView":
                UIScrollView scrollView = GetOrCreateScrollView(parent, name);
                go = scrollView.gameObject;
                UIPanel panel = scrollView.GetComponent<UIPanel>();
                Vector4 region = panel.baseClipRegion;
                region.x = widgetPos.x;
                region.y = widgetPos.y;
                region.z = (int)float.Parse(widgetCfg["width"].ToString());
                region.w = (int)float.Parse(widgetCfg["height"].ToString());
                panel.baseClipRegion = region;
                break;
            default:
                Debug.Log("[PSD2NGUI]: The type '" + type + "' has yet not implemented. Node:"+name);
                UIWidget unknown = GetOrCreateEmpty(parent, name);
                go = unknown.gameObject;
                unknown.transform.localPosition = widgetPos;
                unknown.width = (int)float.Parse(widgetCfg["width"].ToString());
                unknown.height = (int)float.Parse(widgetCfg["height"].ToString());
                unknown.depth = depth;
                break;
        }
        EditorUtility.SetDirty(go);
        if (widgetCfg["children"] != null)
        {
            ArrayList children = widgetCfg["children"] as ArrayList;
            foreach (Hashtable child in children)
            {
                ApplyWidget(go, widgetCfg, child);
            }
        }
    }

    static UIScrollView GetOrCreateScrollView(GameObject parent, string name)
    {
        UIScrollView scrollView = parent.GetComponentsInChildren<UIScrollView>().FirstOrDefault(s => s.name == name);
        if (scrollView == null)
        {
            UIPanel panel = NGUISettings.AddPanel(parent);
            panel.clipping = UIDrawCall.Clipping.SoftClip;
            scrollView = panel.gameObject.AddMissingComponent<UIScrollView>();
            scrollView.name = name;
            panel.gameObject.name = name;
            panel.depth = 2;
        }
        return scrollView;
    }

    static UIWidget GetOrCreateEmpty(GameObject parent, string name)
    {
        UIWidget empty = parent.GetComponentsInChildren<UIWidget>().FirstOrDefault(s => s.name == name);
        if (empty == null)
        {
            empty = NGUISettings.AddWidget(parent);
            empty.name = name;
            empty.gameObject.name = name;
        }
        return empty;
    }

    static UILabel GetOrCreateLabel(GameObject parent, string name)
    {
        UILabel label = parent.GetComponentsInChildren<UILabel>().FirstOrDefault(s => s.name == name);
        if (label == null)
        {
            label = NGUISettings.AddLabel(parent);
            label.name = name;
            label.gameObject.name = name;
        }
        return label;
    }

    static UI2DSprite GetOrCreate2DSprite(GameObject parent, string name, bool isButton)
    {
        UI2DSprite sprite = parent.GetComponentsInChildren<UI2DSprite>().FirstOrDefault(s => s.name == name);
        if (sprite == null)
        {
            sprite = NGUISettings.Add2DSprite(parent);
            sprite.name = name;
            sprite.gameObject.name = name;
            if (isButton)
            {
                NGUITools.AddWidgetCollider(sprite.gameObject);
            }
        }
        return sprite;
    }

    static UIPanel GetOrCreatePanel(string name)
    {
        UIRoot root = UIRoot.list[0];
        UIPanel[] panels = root.GetComponentsInChildren<UIPanel>();
        foreach (UIPanel p in panels)
        {
            if (p.name == name)
            {
                return p;
            }
        }
        UIPanel panel = NGUISettings.AddPanel(root.gameObject);
        panel.name = name;
        panel.gameObject.name = name;
        return panel;
    }

    [MenuItem("Assets/PSD TO NGUI/Import PSD Data", true)]
    static bool ValidateImportPSDData()
    {
        Object o = Selection.activeObject;

        if (o == null)
            return false;
        if (o.GetType() == typeof(TextAsset))
        {
            Hashtable ht = ((TextAsset)o).text.hashtableFromJson();
            bool valid = ht != null && ((string)ht["UIType"]) == "Panel";
            return valid;
        }

        return false;
    }
}
